package com.wpen.unit.web.advice;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;

import org.apache.ibatis.exceptions.TooManyResultsException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.wpen.unit.commun.BaseResponse;
import com.wpen.unit.exception.BizException;
import com.wpen.unit.web.WebVariables;

import lombok.extern.slf4j.Slf4j;

/**
 * 异常拦截处理
 * 
 * @author Wang Peng
 * @date 2022-12-06
 */
@RestControllerAdvice
@Slf4j
public class WebExceptionAdvice {

    // 捕捉业务异常
    @ExceptionHandler(BizException.class)
    public BaseResponse businessException(HttpServletRequest request, Exception ex) {
        BizException exception = (BizException) ex;
        String code = exception.getErrCode();
        String msg = exception.getMessage();
        return setResponseInfo(request, code, msg);
    }

    // 捕捉验证异常
    @ExceptionHandler(ValidationException.class)
    public BaseResponse validationException(HttpServletRequest request, Exception ex) {
        ValidationException exception = (ValidationException) ex;
        String code = "ErrVdt";
        String msg = exception.getMessage();
        return setResponseInfo(request, code, msg);
    }

    @ExceptionHandler(BindException.class)
    public BaseResponse methodArgumentNotValidException(HttpServletRequest request, Exception ex) {
        BindException exception = (BindException) ex;
        List<ObjectError> errors = exception.getAllErrors();
        Set<String> errorSet = new HashSet<>();
        for (ObjectError objectError : errors) {
            String fieldName = "";
            if (objectError instanceof FieldError) {
                FieldError fieldError = (FieldError) objectError;
                fieldName = fieldError.getField();
            }
            errorSet.add(fieldName + ":" + objectError.getDefaultMessage());
        }
        String code = "ErrVdt";
        String msg = errorSet.toString();
        return setResponseInfo(request, code, msg);
    }

    // 捕捉DB异常
    @ExceptionHandler(TooManyResultsException.class)
    public BaseResponse tooManyResultsException(HttpServletRequest request, Exception ex) {
        String code = "ErrQdb";
        String msg = "TooManyResultsException->数据库查询返回记录数大于1，查询异常。";
        return setResponseInfo(request, code, msg);
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public BaseResponse duplicateKeyException(HttpServletRequest request, Exception ex) {
        String code = "ErrUdb";
        Throwable throwable = ex.getCause();
        String error = "";
        if (throwable != null) {
            error = throwable.getMessage();
        }
        if (error == null || "".equals(error)) {
            error = ex.getMessage();
        }
        if (error == null || "".equals(error)) {
            error = "DuplicateKeyException->数据库更新失败";
        }
        return setResponseInfo(request, code, error);
    }

    // 捕捉其他所有异常
    @ExceptionHandler(Exception.class)
    public BaseResponse globalException(HttpServletRequest request, Throwable ex) {
        log.error(ex.getMessage(), ex);
        String errcode = null;
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            errcode = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
        } else {
            errcode = String.valueOf(HttpStatus.valueOf(statusCode));
        }
        String code = errcode;
        String msg = ex.getMessage() + "[" + ex.getClass() + "]";
        return setResponseInfo(request, code, msg);
    }

    private BaseResponse setResponseInfo(HttpServletRequest request, String code, String msg) {
        BaseResponse resp = new BaseResponse();
        resp.setCode(code);
        resp.setMsg(msg);
        // 耗时
        long causeTime = System.currentTimeMillis() - (Long) request.getAttribute(WebVariables.START_TIME);
        resp.setExpms(causeTime);
        // 日志输出
        request.setAttribute(WebVariables.RESPONSE_RESULT, resp);
        return resp;
    }

}
